<template>
  <div class="talk"
       :style="{
         padding: `${this.padding[0]}px ${this.padding[1]}px ${this.padding[2]}px ${this.padding[3]}px`
       }">
    <!--TOOD -->
    <div class="talk-input-com" v-if="position === 'top'" v-bar
      :style="{
        height: position === 'top' ? `${Number.parseInt(height) - 35}px` : height,
        marginTop: position === 'top' ? '40px' : '0',}">
      <div>
        <zz-upload-list listWidth="100%" :files="replyFiles"></zz-upload-list>
        <div class="talk-input"
             v-focus="{isFocus: isFocus}"
             ref="editor"
             @input="handleInput"
             @blur="handleBlur"
             @focus="handleFocus"
             @paste="handlePaste"
             @keydown.enter = 'handleKeyDown'
             :data-text="holder"
             :style="{
                width: width,
                background: background,
                height: height,
                paddingLeft: position === 'top' ? '5px' : '7px',
                marginBottom: isFoot ? '10px' : 0}"
             :class="{
               talkBorder: !isBorder,
               textIndent: upReplyName !== '',
               onlyHeight: openHeight,
               simpleHeight: openSimple}"
             contenteditable="true">
        </div>
      </div>
    </div>
    <div class="talk-input talk-socrll"
         v-if="position === 'bottom'"
         v-focus="{isFocus: isFocus}"
         ref="editor"
         @input="handleInput"
         @blur="handleBlur"
         @focus="handleFocus"
         @paste="handlePaste"
         @keydown.enter = 'handleKeyDown'
         :data-text="holder"
         :style="{
                width: width,
                background: background,
                height: height,
                paddingLeft: position === 'top' ? '5px' : '10px',
                marginBottom: isFoot ? '10px' : 0}"
         :class="{
               talkBottom: isInside,
               talkBorder: !isBorder,
               textIndent: upReplyName !== '',
               onlyHeight: openHeight,
               simpleHeight: openSimple}"
         contenteditable="true">
    </div>

    <div class="reply-man" v-if="upReplyName !== ''">
      <span>回复 <span class="reply-span">{{upReplyName}}</span>:</span>
      <i
        @click="delReplyName"
        v-if="showDelReply"
        class="iconfont icon-x icon-talk-x"></i>
    </div>

    <div class="clear talk-handle un-select relative"  v-if="!openSimple" :class="{handleMargin: isInside}">
      <div class="left clear" :class="{'talk-position-top': position === 'top'}">
        <!--上传文件-->
        <zz-upload
          v-if="isUpload"
          :isTip="isTip"
          :type="fileType"
          class="talk-upload"
          :class="{'talk-upload-weight': isWeight}"
          @updateFile="updateFileHandel"
          style="margin: 6px 8px 0 6px"></zz-upload>

        <!--表情-->
        <div style="margin-top: 4px" v-if="isFace" class="face" contenteditable="false" disabled="true">
          <i class="iconfont icon-smile" @click.stop="shareFace" contenteditable="false" ref="faceContainer"><span v-if="isTip">表情</span></i>
          <div class="face-container" :style="{top: `${faceTop}px`, left: `${faceLeft}px`}" v-if="faceVisible" contenteditable="false">
            <i class="iconfont icon-up"></i>
            <div class="face-list">
              <img
                width = '27'
                height = '27'
                v-for="(value, key) in faceImg"
                @click.stop="handleFaceClick(`${$site.libServer}/front/face/${key}.png`, value)"
                :title="value"
                :src= "`${$site.libServer}/front/face/${key}.png`" />
            </div>
          </div>
        </div>

        <!--@成员-->
        <div style="margin-top: 4px" class="at margin-t" v-if="isAt" contenteditable="false" disabled="true">
          <i class="iconfont icon-at"
             ref="at"
             @click.stop="shareAt"
             contenteditable="false"><span v-if="isTip">成员</span>
          </i>
          <div class="atWho" v-if="atVisible" :style="{top: `${atDialogTop}px`}">
            <div
              contenteditable="false"
              v-for="item in members"
              v-if="item.man_type !== 1"
              @click.stop="handleAtClick(item)">{{item.mname || item.memberName || item.name || item.member_name}}</div>
          </div>
          <zz-retrieve
            ref="weiboRetrieve"
            conWidth = '170px'
            @clickCallBack="clickCallBack"
            :isborder = false
            :multiple = false
            textCompanyArr="@全公司"
            textDepartArr="@部门"
            type = 'other'
            rId = "weibo_retrieve"
          ></zz-retrieve>
        </div>
      </div>

      <slot name="directionTag"></slot>
      <slot name="foot-left"></slot>
      <div class="right talk-foot">
        <slot name="foot-right" v-if="isFoot"></slot>
        <small class="length mr10">{{conNuM}}/{{max}}</small>
        <span class="newline_pm" v-if="isKeyup && isFoot">Ctrl+Enter键换行</span>
        <button class="send button-block" v-if="isFoot" @click="submit">发送</button>
      </div>
    </div>

    <zz-upload-list listWidth="100%" :files="replyFiles" v-if="position === 'bottom'"></zz-upload-list>
  </div>
</template>

<script>
  import {
    /* closest, */ getOffset, /* getPrecedingRange, */
    getRange/* , applyRange */ /* getAtAndIndex */
    /* scrollIntoView, */
  } from './util'
  import img from './face_img'
  export default {
    name: 'zz-talk',
    props: {
      // 默认显示的文字
      innerPropsText: {
        type: String,
        default: ''
      },
      width: {
        type: String,
        default: '100%'
      },
      // 高度
      height: {
        type: String,
        default: '100px'
      },
      // 操作栏是否显示提示语
      isTip: {
        type: Boolean,
        default: true
      },
      // @人员 表情位置
      position: {
        type: String,
        default: 'bottom'
      },
      // 是否直接Enter键 发送
      isKeyup: {
        type: Boolean,
        default: true
      },
      // 是否自动设置光标
      isFocus: {
        type: Boolean,
        default: true
      },
      // 是否开启简单模式
      isSimple: {
        type: Boolean,
        default: false
      },
      // 是否打开上传
      isUpload: {
        type: Boolean,
        default: true
      },
      // 是否打开表情
      isFace: {
        type: Boolean,
        default: true
      },
      // 是否打开@人员
      isAt: {
        type: Boolean,
        default: true
      },
      // 是否开启高度自动缩放
      isHeight: {
        type: Boolean,
        default: false
      },
      // 是否显示底部
      isFoot: {
        type: Boolean,
        default: true
      },
      // 是否显示边框
      isBorder: {
        type: Boolean,
        default: true
      },
      padding: {
        type: Array,
        default: function () {
          return [0, 0, 0, 0]
        }
      },
      // 背景颜色
      background: {
        type: String,
        default: '#f6fcfc'
      },
      // 是否加粗字体
      isWeight: {
        type: Boolean,
        default: true
      },
      holder: {
        type: String,
        default: '请输入内容'
      },
      // 评论时， 回复的评论Id
      parentId: {
        type: Number
      },
      // 评论时， 评论人的Id
      upReplyId: '',
      // 评论时， 评论人的名字
      upReplyName: {
        type: String,
        default: ''
      },
      // @人员时 是否用选择人的组件
      isAtAll: {
        type: Boolean,
        default: false
      },
      // 上传文件类型
      fileType: {
        type: Array,
        default: function () {
          return []
        }
      },
      // 鼠标离开时，是否触发事件
      isBlur: {
        type: Boolean,
        default: false
      },
      // 是否有权限
      auth: null,
      // 本地临时存储的localStorage的id
      localId: {
        type: String,
        default: ''
      },
      // @员工时是否用工号
      isWeqiaNo: {
        type: Boolean,
        default: false
      },
      max: {
        type: Number,
        default: 1000
      },
      // 是否必填
      required: {
        type: Boolean,
        default: true
      },
      // 操作按钮是否放在里面
      isInside: {
        type: Boolean,
        default: false
      }
    },
    directives: {
      focus: {
        inserted: (el, binding) => {
          // 聚焦元素
          const {value} = binding
          if (value.isFocus) {
            el.focus()
          }
        }
      }
    },
    data () {
      return {
        openSimple: false,
        openHeight: false,
        showDelReply: true,
        replyFiles: [],
        firstClick: true,
        faceVisible: false,
        atVisible: false,
        closeAt: false,
        focus: false,
        sel: null,
        lastEditRange: 0,
        atTop: 0,
        atLeft: 0,
        faceImg: img,
        faceTop: 17,
        faceLeft: 17,
        atDialogTop: 18,
        sendData: '',
        hasComposition: false,
        atwho: null,
        showPaint: false,
        viewPieImage: '',
        setLocalStorageThrottle: null,
        members: [],
        conNuM: 0
      }
    },
    computed: {
      style () {
        if (this.atwho) {
          const { x, y } = this.atwho
          const { wrap } = this.$refs
          if (wrap) {
            const offset = getOffset(wrap)
            const left = x + window.pageXOffset - offset.left + 'px'
            const top = y + window.pageYOffset - offset.top + 'px'
            return { left, top }
          }
        }
        return null
      }
    },
    created () {
      this.openSimple = this.isSimple
      this.openHeight = this.isHeight
      this.setLocalStorageThrottle = this.$Throttle(this.setLocalStorage, 1000)
    },
    mounted () {
      if (this.innerPropsText) {
        this.insertTextAtCursor(this.innerPropsText)
      }
      this.$nextTick(() => {
        if (this.localId) {
          this.$refs.editor.innerHTML = window.localStorage.getItem(this.localId)
        }
      })
    },
    beforeDestroy () {
      window.localStorage.setItem(this.localId, '')
    },
    watch: {
      isSimple (status) {
        this.openSimple = status
      },
      innerPropsText () {
        this.insertTextAtCursor(this.innerPropsText)
      }
    },
    methods: {
      // 发送数据
      submit () {
        this.sendData = ''
        let child = this.$refs.editor.childNodes
        this.getReplyData(child)

        if (this.replyFiles.length > 0) {
          this.$fileUpload.getFileUUID().then((files) => {
            this.submitParent(files)
          })
        } else {
          this.submitParent()
        }
      },
      submitParent (files) {
        // 去掉字符串开头与结尾的空格
        this.sendData = this.sendData.replace(/^\s+|\s+$/g, '')
        if (this.sendData === '' && this.required && !files) {
          this.$message.warning('请输入内容')
          return false
        }

        if (this.sendData.length > this.max) {
          this.$message.warning(`内容不能超过${this.max}个字符`)
          return
        }
        const obj = {
          value: this.sendData,
          parentId: this.parentId,
          upReplyId: this.upReplyId,
          files: files
        }
        this.$emit('sendData', obj)
        this.$refs.editor.innerText = ''
        this.$fileUpload.removeFiles()
        this.replyFiles = []
        this.sendData = ''
        this.conNuM = 0
      },
      updateFileHandel (items) {
        this.replyFiles = items
      },
      delReplyName () {
        this.$emit('delReplyName')
      },
      // 转换html标签
      getReplyData (childs) {
        for (let i = 0; i < childs.length; i++) {
          switch (childs[i].nodeName) {
            case '#text':
              this.sendData += childs[i].nodeValue
              break
            case 'IMG':
              let faceValue = childs[i].getAttribute('value')
              this.sendData += '[' + faceValue + ']'
              break
            case 'SPAN':
              let atValue = childs[i].getAttribute('value')
              this.sendData += '@[' + atValue + ']'
              break
            case 'DIV':
              this.sendData += '\n'
              this.getReplyData(childs[i].childNodes)
          }
        }
      },

      // enter 提交数据
      handleKeyDown (e) {
        e.preventDefault()
        e.stopPropagation()
        if (e.ctrlKey) {
          this.newLine()
          return
        }
        if (this.isKeyup) {
          this.submit()
        } else {
          this.newLine()
        }
      },

      // ctrl + enter 换行
      newLine () {
        document.execCommand('InsertParagraph')
      },
      // 监听复制事件
      handlePaste (e) {
        const pasteEvent = e
        const data = pasteEvent.clipboardData
        let text
        if (data.types.includes('Files')) {
          this.$fileUpload.addFiles(data.files)
        } else {
          text = data.getData('text/plain') || data.getData('text/html')
        }
        if (text) {
          const flaotdiv = document.createElement('div')
          flaotdiv.innerText = text
          const realText = flaotdiv.innerText
          this.insertTextAtCursor(realText)
          e.preventDefault()
          return false
        } else {
          e.preventDefault()
          return false
        }
      },

      insertTextAtCursor (text) {
        const editor = this.$refs.editor
        const childNodes = editor.childNodes
        const sel = window.getSelection()
        const textLastChar = text.substring(text.length - 1)
        const fulltext = editor.innerText
        const newLineNode = document.createTextNode('\n')
        let lastChar = null
        let lastNode = null
        if (fulltext !== '') {
          lastChar = fulltext.substring(fulltext.length - 1)
          lastNode = this.getLastNode(childNodes)
        }
        let needsExtra = (textLastChar === '\n' && lastChar !== '\n' && (lastChar === null || (sel.anchorNode === lastNode && sel.anchorOffset === lastNode.length) || (sel.focusNode === lastNode && sel.focusOffset === lastNode.length)))

        const textNode = document.createTextNode(text)
        let range = null
        range = sel.getRangeAt(0)
        range.deleteContents()
        // 修复chomce 第一行 按下没有换行的BUG
        if (needsExtra) {
          if (!this.$Browser().gecko) {
            range.insertNode(newLineNode)
          }
        }
        range.insertNode(textNode)
        // 新建 range
        range = document.createRange()
        range.setStartAfter(textNode)
        range.collapse(true)

        // 光标移到最后
        sel.removeAllRanges()
        sel.addRange(range)
        this.handleInput(text.length)
      },

      getLastNode (childNodes) {
        for (let i = childNodes.length - 1; i >= 0; i--) {
          if (childNodes[i].childNodes.length > 0) {
            let lastNode = this.getLastNode(childNodes[i].childNodes)
            if (lastNode !== null) {
              return lastNode
            } else {
              continue
            }
          } else if (childNodes[i].data !== '') {
            return childNodes[i]
          }
        }
        return null
      },

      // 显示 选择表情
      shareFace () {
        this.faceVisible === true ? this.faceVisible = false : this.faceVisible = true
        if (this.faceVisible) {
          this.setFacePosition()
          this.moveFocus()
          this.addEvent()
        }
      },
      setFacePosition () {
        const rect = this.$refs.faceContainer.getBoundingClientRect()
        this.faceTop = rect.top
        this.faceLeft = rect.left
        if (rect.bottom + 284 > window.innerHeight) {
          this.faceTop = rect.top - 290
        }
      },
      setAtDialogPosition () {
        const rect = this.$refs.at.getBoundingClientRect()
        if (rect.bottom + 150 > window.innerHeight) {
          this.atDialogTop = -165
        }
      },
      handleFocus () {
        this.openSimple = false
        this.openHeight = false
        this.$emit('handleFocus')
        if (this.closeAt) {
          this.atVisible = false
        }
      },
      handleBlur (e) {
        let child = this.$refs.editor.childNodes
        this.getReplyData(child)
        if (!this.sendData) {
          if (this.isHeight) {
            this.openHeight = true
          }
        }
        if (this.isBlur) {
          this.$emit('blur', this.sendData)
          this.sendData = ''
        }
        this.handleInput(e)
      },
      handleInput (e) {
        this.sel = getRange()
        this.lastEditRange = getRange().getRangeAt(0)
        if (this.localId) {
          this.setLocalStorageThrottle()
        }
        if (e.target) {
          this.conNuM = e.target.innerText.length
        } else {
          this.conNuM += e
        }
        if (this.conNuM > this.max) {
          this.$message.warning('已经超过最大字数')
        }
      },

      // 存储临时数据
      setLocalStorage () {
        window.localStorage.setItem(this.localId, this.$refs.editor.innerHTML)
      },

      // 移动光标到最后
      moveFocus () {
        if (this.firstClick) {
          this.$refs.editor.focus()
          this.firstClick = false
        } else {
          if (this.$Browser().gecko || this.$Browser().trident) {
            this.$refs.editor.focus()
          }
        }
      },

      // 点击表情 回调
      handleFaceClick (src, value) {
        const range = this.lastEditRange
        const r = range.cloneRange()
        r.setStart(r.endContainer, range.endOffset)
        let img = document.createElement('img')
        let textnbsp = document.createTextNode(' ')
        img.src = src
        img.setAttribute('value', value)
        range.insertNode(textnbsp)
        range.insertNode(img)
        range.setStart(textnbsp, 0)
        range.setEnd(textnbsp, 1)
        this.sel.removeAllRanges()
        this.sel.addRange(range)
        this.sel.collapseToEnd(range)
      },

      // 获取 显示@成员列表
      shareAt () {
        if (this.isAtAll) {
          this.$refs.weiboRetrieve.show()
        } else {
          this.atVisible === true ? this.atVisible = false : this.atVisible = true
          if (this.atVisible) {
            this.setAtDialogPosition()
            this.closeAt = false
            this.addEvent()
            this.moveFocus()
            let data = {}
            if (this.auth.isManList) {
              this.members = this.auth.manList
            } else {
              if (this.auth.query) {
                this.auth.query.forEach(item => {
                  data[item.key] = item.value
                })
              } else {
                data[this.auth.queryName] = this.auth.id
              }
              this.$axios({
                method: 'post',
                url: this.auth.url,
                data: this.$qs.stringify(data, {indices: false})
              }).then(res => {
                if (res.data.errorMsg) {
                  this.$message.error(res.data.errorMsg)
                } else {
                  this.members = res.data.list
                }
              })
            }
          }
        }
      },

      // @人员 选中事件
      clickCallBack (node) {
        this.handleAtClick(node)
      },
      addEvent () {
        document.addEventListener('click', this.onDocumentMouseDown, false)
      },
      removeEvent () {
        const self = this
        document.removeEventListener('click', self.onDocumentMouseDown, false)
      },
      onDocumentMouseDown () {
        this.atVisible = false
        this.faceVisible = false
        this.closeAt = true
        this.removeEvent()
      },

      // 设置at框位置
      setAtPosition () {
        const rect = this.$refs.at.getBoundingClientRect()
        this.atTop = rect.top + 20
        this.atLeft = rect.left
      },

      // 点击成员回调
      handleAtClick (item) {
        let name = item.mname || item.memberName || item.name || item.member_name || item.mName || item.label
        let mNo = item.mNo || item.wid || item.member_id || item.id || ''
        if (this.isWeqiaNo) {
          mNo = item.weqiaNo || item.member_no
        }
        if (this.$refs.editor.innerText.includes(`@${name}`)) {
          return
        }
        let range = this.lastEditRange
        let r = range.cloneRange()
        let atSpan = document.createElement('span')
        let atSpace = document.createTextNode('\u00A0')
        r.setStart(r.endContainer, range.endOffset)
        atSpan.innerText = `@${name}`
        let colon = ':'
        if (item.isDepart) {
          colon = '：'
        }
        atSpan.setAttribute('value', `${name}${colon}${mNo}`)
        atSpan.setAttribute('contenteditable', false)
        range.insertNode(atSpace)
        range.insertNode(atSpan)
        range.setStart(atSpace, 0)
        range.setEnd(atSpace, 1)
        this.sel.removeAllRanges()
        this.sel.addRange(range)
        this.sel.collapseToEnd(range)
      }
    }
  }
</script>

<style lang="scss">
  .talk{
    position: relative;
    .simpleHeight{
      height: 35px !important;
    }
    .onlyHeight{
      height: 35px !important;
    }
    .icon-talk-x{
      font-size: $font-size-smallest;
      position: absolute;
      top: -7px;
      right: -13px;
      color: #fff;
      cursor: pointer;
      background: $red;
    }
    .reply-man{
      position: absolute;
      top: 8px;
      left: 12px;
      color: $color-grid;
      font-size: $font-size-small;
      .reply-span{
        display: inline-block;
        vertical-align: top;
        width: 45px;
        @include ellipsis
      }
    }
    .talk-input{
      margin:0 auto 10px auto;
      line-height: 20px;
      @include input-l(95.5%);
      white-space: pre-line;
      justify-content: center;
      &:focus{
        border: 1px $color solid;
      }
      img{
        width: 20px;
        height: 20px;
        vertical-align: text-top;
      }
      span{
        color: $color;
      }
    }
    .talk-socrll{
      overflow: hidden;
      overflow-y: auto;
      word-break: break-all;
    }

    .talkBottom{
      padding: 7px 10px 25px 10px;
    }
    .handleMargin{
      margin-top: -31px;
      margin-left: 1px;
      margin-right: 1px;
      background: #fff;
    }
    .textIndent{
      text-indent: 100px;
    }
    .talk-handle{
      color: #949a98;
      .talk-position-top{
        position: absolute;
        top: -150px;
        left: 0;
      }
    }
    .talk-upload{
      float: left;
      height: 19px;
    }
    .talk-upload-weight{
      i{
        font-weight: 700;
      }
    }
    .face{
      float: left;
      vertical-align: top;
      position: relative;
      .icon-smile{
        cursor: pointer;
        font-size: 20px;
        color: $color-grid;
        &:before{
          float: left;
        }
        &:hover{
          color: $color;
        }
        span{
          font-size: $font-size-smallest;
          margin: 5px 0 0 4px;
          float: left;
        }
      }
      .face-container{
        position: fixed;
        z-index:2;
        .icon-up{
          font-size: $font-size-large;
          color: $color-grid;
          background: #fff;
        }
        .face-list{
          border-radius: 3px;
          padding: 8px;
          width: 380px;
          height: 268px;
          background: #fff;
          border: 1px #ddd solid;
          margin-top: -4px;
          margin-left: -10px;
          img{
            cursor: pointer;
          }
        }
      }
    }
    .at{
      float: left;
      vertical-align: top;
      position: relative;
      .icon-at{
        cursor: pointer;
        font-size: 20px;
        color: $color-grid;
        &:before{
          float: left;
        }
        &:hover{
          color: $color;
        }
        span{
          font-size: $font-size-smallest;
          margin: 5px 0 0 4px;
          float: left;
        }
      }
      .atWho{
        width:80px;
        height: 150px;
        background: #fff;
        border-radius: 3px;
        border: 1px solid #ddd;
        padding: 8px;
        overflow: auto;
        position: absolute;
        z-index: 2;
        left: 1px;
        >div{
          line-height: 20px;
          width: 70px;
          font-size: $font-size-smallest;
          @include ellipsis;
          cursor: pointer;
          &:hover{
            color: $color;
          }
        }
      }
    }
    .talkBorder{
      border: none;
      &:focus{
        border: 0 $color solid;
      }
    }
    .newline_pm{
      margin-right: 10px;
      font-size: $font-size-smallest;
    }
    .talk-foot{
      line-height: 30px;
    }
    .margin-t{
      margin: 0 0 0 10px;
    }
  }

</style>
